package com.klxedu.ms.gateway.security.authentication;

import java.util.HashSet;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import com.klxedu.ms.gateway.security.authentication.impl.AuthorizedRoles;

/**
 * 
 * 登录授权认证逻辑对象，对请求的资源进行认证过滤。如果认证失败则返回错误页面。该对象用于Spring Security配置中。
 * 对象中包含2个主要的接口对象IAuthenticateAction和IAuthenticateDetails
 * ，其中IAuthenticateAction为真正用于登录认证的逻辑实现，
 * IAuthenticateDetails用于登录成功后封装用户可访问资源、角色等信息的逻辑实现。
 * 
 * @author GuoR
 * @createDate 2016年5月17日
 */
public class CustomAuthenticationUserDetailsService implements UserDetailsService {

	private IAuthenticateAction authenticateAction;

	private IAuthenticateRoles authenticateRoles;

	public CustomAuthenticationUserDetailsService(IAuthenticateAction authenticateAction) {
		this.authenticateAction = authenticateAction;
	}

	public CustomAuthenticationUserDetailsService(IAuthenticateAction authenticateAction,
			IAuthenticateRoles authenticateRoles) {
		this.authenticateAction = authenticateAction;
		this.authenticateRoles = authenticateRoles;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		IAuthenticatedUser authenticatedUser = getAuthenticateAction().doAuthenticate(username);
		// 其实这步骤并没必要，因为验证失败直接会抛出异常，根本不会返回null的时候
		// 但避免在其他情况，对IAuthenticateAction实现的时候出现这种情况，因此暂时保留
		if (authenticatedUser == null) {
			throw new UsernameNotFoundException("用户不存在: " + username);
		}
		// 增加授权角色
		Set<GrantedAuthority> grantedAuths = new HashSet<GrantedAuthority>();
		grantedAuths.add(new SimpleGrantedAuthority("IS_AUTHENTICATED_ANONYMOUSLY"));

		// 登录用户的授权资源设置，如果authenticateDetails==null，则把当前登录授权用户对象代替授权资源
		if (getAuthenticateRoles() != null) {
			AuthorizedRoles details = getAuthenticateRoles().doDetails(authenticatedUser);
			if (details.getUserRoles() != null) {
				for (String role : details.getUserRoles()) {
					grantedAuths.add(new SimpleGrantedAuthority(role));
				}
			}
		}
//		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		CustomUserDatails userDetails = new CustomUserDatails(username, authenticatedUser.getPassword(),
				grantedAuths);
		userDetails.setExtendAccountInfo(authenticatedUser);
		return userDetails;
	}

	public IAuthenticateAction getAuthenticateAction() {
		return authenticateAction;
	}

	public void setAuthenticateAction(IAuthenticateAction authenticateAction) {
		this.authenticateAction = authenticateAction;
	}

	public IAuthenticateRoles getAuthenticateRoles() {
		return authenticateRoles;
	}

	public void setAuthenticateRoles(IAuthenticateRoles authenticateRoles) {
		this.authenticateRoles = authenticateRoles;
	}

}
